import 'dart:async';
import 'dart:convert';
import 'package:dio/dio.dart';
import 'dart:io';
import 'package:package_info_plus/package_info_plus.dart';

import '../common/util/val_app_state_tool.dart';
import '../common/util/val_device_info_loader.dart';

typedef AccessFailBlock = void Function();

class ValDioFetchKit {
  static ValDioFetchKit? _instance;
  bool isDebug = false;
  Dio dio = Dio();
  String baseUrl = "";
  Map<String, dynamic> headers = {};

  AccessFailBlock? accessFailBlock;

  static ValDioFetchKit getInstance() {
    _instance ??= ValDioFetchKit._internal();
    return _instance!;
  }

  //初始化...
  ValDioFetchKit._internal() {
    initHeaders();
  }


  Future<void> initHeaders() async {
    PackageInfo packageInfo = await PackageInfo.fromPlatform();
    String deviceId = await ValDeviceInfoLoader.getDeviceId();
    String model = await ValDeviceInfoLoader.getDeviceModel();
    //初始化
    headers['device-id'] = deviceId; // 设备id或者udid，保证当前设备唯一值。
    headers['model']     = model; // 设备型号
    if (Platform.isAndroid) {
      headers['platform']  = 'Android';

    } else if (Platform.isIOS) {
      headers["platform"]  = "iOS";
    }
    headers['pkg']   = packageInfo.packageName; // 包名
    headers['ver']   = packageInfo.version; // 版本 例如1.0.0，读取实际配置的版本号
    headers['p_ver'] = packageInfo.buildNumber; // build number
    headers['kst']   = '1'; // 固定传1
    headers['sys_lan'] = 'en'; // 手机系统语言 如英文en
  }


  void setup(String baseUrl, {
    bool isDebug = true,
    AccessFailBlock? accessFailBlock,
  }) {
    this.baseUrl = baseUrl;
    this.isDebug = isDebug;
    this.accessFailBlock = accessFailBlock;
    dio.options = getBaseOptions();
    // dio.interceptors.add(ErrorInterceptor()); // 异常拦截器
    // dio.interceptors.add(ResponseInterceptor()); // 响应拦截器
    // dio.interceptors.add(HeaderInterceptor()); // 请求拦截器
    // dio.interceptors.add(LogInterceptor(responseBody: true)); //是否开启请求日志
    //  dio.interceptors.add(CookieManager(CookieJar()));//缓存相关类，具体设置见https://github.com/flutterchina/cookie_jar
  }

  /// 基础配置
  BaseOptions getBaseOptions() {
    return BaseOptions(
      connectTimeout: 20000,
      receiveTimeout: 40000,
      responseType: ResponseType.json,
      contentType: 'application/json; charset=utf-8',
      baseUrl: baseUrl,
    );
  }

  Future<Options> getOptions({String? contentType,
    ResponseType? responseType,
    Map<String, dynamic>? header}) async {
    // var headers = await this.headers;
    Map<String, dynamic>? customHeader = header ?? headers;

    // String token = await ApplicationInfo.getInstance().loginToken;
    if (ValAppStateTool().token.isNotEmpty) {
      customHeader['Authorization'] = 'Bearer' + ValAppStateTool().token;
    }
    // else if (customHeader.keys.contains('Authorization')) {
    //   customHeader.remove('Authorization');
    // }

    return Options(
      sendTimeout: 20000,
      receiveTimeout: 40000,
      responseType: ResponseType.json,
      contentType: contentType ?? 'application/json; charset=utf-8',
      headers: customHeader, //header ?? headers,
    );
  }

  // /// 请求头
  // Future<Map<String, dynamic>> get headers async {

  // return headerMap;
  // }

  // get请求
  Future<void> getJsonWithUrl(String url,
      Map<String, dynamic> params,
      Function successCallBack,
      Function errorCallBack, {
        String? contentType,
        Map<String, dynamic>? header,
        CancelToken? cancelToken,
      }) async {
// Map.fromEntries(params.fields),
    Response response;
    try {
      if (params == null) {
        var option = await getOptions(header: header,contentType: contentType ?? 'application/json; charset=utf-8',);
        response =
        await dio.get(url, options: option, cancelToken: cancelToken);
      } else {
        var option = await getOptions(header: header, contentType: contentType ?? 'application/json; charset=utf-8',);
        response = await dio.get(url,
            queryParameters: params, options: option, cancelToken: cancelToken);
      }
    } on DioError catch (error) {
      _error(errorCallBack, error.message);
      return;
    }
    _responseHttp(response, successCallBack, errorCallBack);
  }

  /// post请求
  /// 请求参数：json格式
  Future<void> postJsonWithUrl(String url,
      dynamic params,
      Function successCallBack,
      Function errorCallBack, {
        String? contentType,
        dynamic header,
        CancelToken? cancelToken,
        encrypt = true, //是否开启url和参数加密
      }) async {
    Response response;
    try {
      if (params == null) {
        var option = await this.getOptions(header: header);
        response =
        await dio.post(url, options: option, cancelToken: cancelToken);
      } else {
        var option = await getOptions(
            header: header, contentType: contentType);
        response = await dio.post(url,
            data: params, options: option, cancelToken: cancelToken);
      }
    } on DioError catch (error) {
      _error(errorCallBack, error.message);
      return;
    }

    _responseHttp(response, successCallBack, errorCallBack);
  }

  /// post请求 图片请求 (只能上传一张图片)
  /// 请求参数：formData
  /// Map.fromEntries(formData.fields);
  Future<void> uploadFile({
    required String url,
    required Function successCallBack,
    required FormData formData,
    Map<String, dynamic>? params,
    Function? errorCallBack,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
  }) async {
    Response response;
    try {
      var option = await this.getOptions(contentType: 'multipart/form-data');
      response = await Dio().post(url,
          data: formData,
          queryParameters: params,
          options: option,
          cancelToken: cancelToken,
          onSendProgress: onSendProgress
      );
    } on DioError catch (error) {
      if (errorCallBack != null) {
        _error(errorCallBack, error.message);
      }
      return;
    }
    _responseHttp(response, successCallBack, errorCallBack);
  }

  void _responseHttp(Response response,
      Function successCallBack,
      Function? errorCallBack,) {
    String dataStr = json.encode(response.data);
    Map<String, dynamic> dataMap = {};
    try {
      dataMap = json.decode(dataStr);
    }
    catch (e) {
      print('解析返回数据异常：$e');
    }

    if (dataMap == null) {
      if (errorCallBack != null) {
        _error(errorCallBack, "请求失败");
      }
    } else if (successCallBack != null) {
      var result = dataMap['data'];
      successCallBack(result == null ? {} : result,
          dataMap['code'], dataMap['msg']);
    }
  }

  //取消请求
  void cancleRequests(CancelToken token) {
    token.cancel("cancelled");
  }

  void _error(Function errorCallBack, String error) {
    if (errorCallBack != null) {
      errorCallBack(error);
    }
  }
}